#!/usr/local/bin/tcsh

#   Copyright (C) 1989 Free Software Foundation, Inc.
#   
#   genclass program enhanced by Wendell C. Baker 
#   (original by Doug Lea (dl@rocky.oswego.edu))

#This file is part of GNU libg++.

#GNU libg++ is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 1, or (at your option)
#any later version.

#GNU libg++ is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.

#You should have received a copy of the GNU General Public License
#along with GNU libg++; see the file COPYING.  If not, write to
#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

set echo_style=both
#
# genclass -list [proto ...]
# genclass -catalog [proto ...]
# genclass type1 {ref|val} proto [out_prefix]
# genclass -2 type1 {ref|val} type2 {ref, val} proto [out_prefix]
#
# Generate classes from prototypes
#
set name=genclass ;
set usage="\n    $name -list [proto ...]\n    $name -catalog [proto ...]\n    $name type1 {ref|val} proto [out_prefix]\n    $name -2 type1 {ref|val} type2 {ref|val} proto [out_prefix]"

switch ("$1")
case -usage:
    #
    # -usage
    #
    echo "usage: $usage";
    exit 0;
    breaksw
case -version:
    #
    # -version
    #
    # <VERSION> is substituted by the build process.
    # We currently use the libg++ version number (extracted from ../Makefile).
    echo "$name: version 2.5.2" ;
    exit 0;
    breaksw;
case -requires:
    #
    # -requires
    #
    # The following line should contain any nonstandard programs
    # which must be in the users's path (i.e. not referenced by a
    # fullpath);it allows one to check a script for dependencies
    # without exhaustively testing its usages.
    # ... in this case genclass depends on nothing else.
    echo ;
    exit 0;
    breaksw;
endsw

# pull it in from the environment
#[ "$TRACE" = "" ] || set -xv 

# Search in standard g++ prototype directory and in the current directory
# NOTE: this variable is edited by the install process
set PROTODIR=/usr/local/lib/c++proto

set pwd=$PWD ;

switch ("$1")
case -list:   #*|-catalog*:
    #
    # genclass -catalog [proto ...]
    # genclass -list [proto ...]
    #
    set option="$1" ;
    shift ;

    switch ($#)
    case 0:
        #
        # -catalog
        # -list
        #
        set select=all ;
        set select_pattern=p ;
        breaksw
    default:
        #
        # -catalog proto ...
        # -list proto ...
        #
        set select="$@" ;
        select_pattern= ;
        foreach i ($@)
            set select_pattern="\
$select_pattern\
/.*$i\$/ p\
" ;
        end ;

        breaksw
    endsw

    #
    # select_pattern is now a (possibly-vacuous) newline-
    # separated list of patterns of the form:
    #
    #     /.*Proto1$/ p
    #     /.*Proto2$/ p
    #     /.*Proto3$/ p
    #
    # or select_pattern is simply ``p'' to select everything

    # Hmmm... not all systems have a fmt program; should we
    # just go ahead and use ``nroff -Tcrt | cat -s'' here?
    set fmt='nroff -Tcrt | cat -s'
    #fmt=fmt ;

    switch ("$option")
    case -catalog:
        #
        # -catalog [proto ...]
        #
        echo "\
Catalog of ${name} class templates\
directories searched:\
    $PROTODIR\
    $pwd\
selecting: $select\
classes available:" ;
        breaksw
    case -list:
        #
        # -list [proto ...]
        #
        # no need to do anything (the list is coming out next)
        breaksw
    endsw 

# The sed script does the following:
# - If it does not end in a .ccP or .hP then
#   it's not a template and we are not intereseted.
# - Get rid of pathname components [s;.*/;;]
# - Just take the template names
# - change quoting conventions and select off what we want to see
# -if it did not pass the patterns, kill it

    ls $pwd $PROTODIR | sed -ne '\
/\.ccP$/ !{ \
   /\.hP$/ !{ \
     d \
   } \
} \
s;.*/;;\
s/\.ccP$//\
s/\.hP$//\
' -e "$select_pattern" | sort -u | switch ("$option")
    case -catalog:
        # The library catalog information preceded the list
        # format the list, and tab in in a bit to make it readable.
        # Re-evaluate $fmt because it might contain a shell command
        eval $fmt | sed -e 's/.*/    &/' ;
        breaksw
    case -list:
        # nothing special, just let the sorted list dribble out
        # we must use cat to receive (and reproduce) the incoming list
        cat ;
        breaksw
    exit 0;
    breaksw
case -2:
    #
    # genclass -2 type1 {ref|val} type2 {ref|val} proto [out_prefix]
    #
    set N=2 ;

    switch ($#)
    case [6]: # genclass -2 type1 {ref|val} type2 {ref|val} proto
       breaksw
    case [7]: # genclass -2 type1 {ref|val} type2 {ref|val} proto out_prefix
       breaksw
    default:
	echo "usage: $usage"  ;
	exit 1;
	breaksw;
    endsw
    shift ;
    breaksw
default:
    #
    # genclass type1 {ref|val} proto [out_prefix]
    #
    set N=1 ;

    switch ($#)
    case [3]: # genclass type1 {ref|val} proto
       breaksw;
    case [4]: # genclass type1 {ref|val} proto out_prefix
       breaksw;
    default:
	echo "usage: $usage"  ;
	exit 1;
	breaksw
    endsw
    breaksw
endsw

#
# Args are now (the point being the leading ``-2'' is gone)
#
#     type1 {ref|val} proto [out_prefix]
#     type1 {ref|val} type2 {ref|val} proto [out_prefix]
#

#
# Quote all of the $1 $2 etc references to guard against
# dynamic syntax errors due to vacuous arguments (i.e. '')
# as sometimes occurs when genclass is used from a Makefile
#

set T1="$1";
set T1NAME="${T1}." ;
set T1SEDNAME="$T1" ;

switch ("$2")
case ref:
     set T1ACC="\&" ;
     breaksw
case val:
     set T1ACC=" " ;
     breaksw
default:
    echo "${name}: Must specify type1 access as ref or val"  ;
    echo "usage: $usage"  ;
    exit 1
    breaksw
endsw

# N is either 1 or 2

switch ($N)
case 1:
    #
    # type1 {ref|val} proto [out_prefix]
    #
    set class="$3" ;

    set T2="" ;
    set T2ACC="" ;
    set T2NAME="";
    breaksw
case 2:
    #
    # type1 {ref|val} type2 {ref|val} proto [out_prefix]
    #
    set class="$5" ;

    set T2="$3";
    set T2NAME="$T2." ;
    set T2SEDNAME="$T2" ;

    switch ("$4")
    case ref:
        set T2ACC="\&" ;
        breaksw;
    case val:
        set T2ACC=" " ;
        breaksw;
    default:
        echo "${name}: Must specify type2 access: ref or val"  ;
	echo "usage: $usage"  ;
	exit 1;
	breaksw;
    endsw
endsw

set defaultprefix="$T1NAME$T2NAME" ;

switch ($#)
case [3]:  # type1 {ref|val} proto
    set replaceprefix="N" ;
    set prefix="$defaultprefix" ;
    breaksw;
case [5]:  # type1 {ref|val} type2 {ref|val} proto
    set replaceprefix="N" ;
    set prefix="$defaultprefix" ;
    breaksw;
case [4]:  # type1 {ref|val} proto out_prefix
    set prefix="$4" ;
    set replaceprefix="Y" ;
    breaksw;
case [6]:  # type1 {ref|val} type2 {ref|val} proto out_prefix
    set prefix="$6" ;
    set replaceprefix="Y" ;
    breaksw;
default:
    echo "${name}: too many arguments"  ;
    echo "usage: $usage"  ;  
    exit 1;
    breaksw;
endsw ;

set src_h=$class.hP
set src_cc=$class.ccP
set out_h=$prefix$class.h;
set out_cc=$prefix$class.cc ;

#
# Note #1: The .h and .cc parts are done separately
#     in case only a .h exists for the prototype
#
# Note #2: Bind the .h and .cc parts to the fullpath
#     directories at the same time to ensure consistency.
#

if (-f $pwd/$src_h) then
    set fullsrc_h=$pwd/$src_h ;
    set fullsrc_cc=$pwd/$src_cc ;
else if ( -f $PROTODIR/$src_h ) then
    set fullsrc_h=$PROTODIR/$src_h ;
    set fullsrc_cc=$PROTODIR/$src_cc ;
else
    echo "${name}: there is no prototype for class $class - file $src_h"  ;
    $0 -list ;
    exit 1;
endif

set CASES="$N$replaceprefix" ;
# CASES is one of { 2Y 2N 1Y 1N }

#
# WATCHOUT - we have no way of checking whether or not
# the proper case type is being used with the prototype.
#
# For example, we have no way of ensuring that any of
# Map variants are specified with the -2 argument set
# Further, we have no way of ensuring that -2 is not
# used with the prototypes which require only one.
#
# The second problem is not serious because it still
# results in correctly-generated C++ code; the first
# problem is serious because it results in C++ code that
# still has ``<C>'' and ``<C&>'' syntax inside it.  Such
# code of course will not compile.
#
# SO THE BEST WE CAN DO - is check for the presence of
# <C> and <C&> AFTER the thing has been generated.
#

switch ($CASES)
case 2Y: # Two output substitutions, change the prefix
    sed < $fullsrc_h > $out_h -e "\
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
s/<C>/$T2/g\
s/<C&>/$T2$T2ACC/g \
s/$T1SEDNAME\.$T2SEDNAME\./$prefix/g\
s/$T1SEDNAME\./$prefix/g\
s/$T2SEDNAME\./$prefix/g\
" ;
    breaksw;
case 2N: # Two output substitutions, use the default prefix
    sed < $fullsrc_h > $out_h -e "\
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
s/<C>/$T2/g\
s/<C&>/$T2$T2ACC/g\
" ;
    breaksw;
case 1Y: # One output substitution, change the prefix
    sed < $fullsrc_h > $out_h -e "
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
s/$T1SEDNAME\./$prefix/g\
" ;
    breaksw;
case 1N: # One output substitution, use the default prefix
    sed < $fullsrc_h > $out_h -e "\
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
" ;
    breaksw;
endsw

fgrep '<C&?>' $out_h > /dev/null
if ( $? == 0) then
    echo "${name}: the $class class requires the -2 syntax for the 2nd type"  ;
    echo "usage: $usage"  ;
    # the user does not get to see the mistakes (he might try to compile it)
    rm $out_h ;
    exit 1;
endif

if ( ! -f $fullsrc_cc ) then
    echo "${name}: warning, class has a .h but no .cc file"  ;
    exit 0;
endif

switch ($CASES)
case 2Y: # Two output substitutions, change the prefix
    sed < $fullsrc_cc > $out_cc -e "\
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
s/<C>/$T2/g\
s/<C&>/$T2$T2ACC/g\
s/$T1SEDNAME\.$T2SEDNAME\./$prefix/g\
s/$T1SEDNAME\./$prefix/g\
s/$T2SEDNAME\./$prefix/g\
"
    breaksw;
case 2N: # Two output substitutions, use the default prefix
    sed < $fullsrc_cc > $out_cc -e "\
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
s/<C>/$T2/g\
s/<C&>/$T2$T2ACC/g\
"
    breaksw;
case 1Y: # One output substitution, change the prefix
    sed < $fullsrc_cc > $out_cc -e "\
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
s/$T1SEDNAME\./$prefix/g\
"
    breaksw;
case 1N: # One output substitution, use the default prefix
    sed < $fullsrc_cc > $out_cc -e "\
s/<T>/$T1/g\
s/<T&>/$T1$T1ACC/g\
"
    breaksw;
endsw

fgrep '<C&?>' $out_h $out_cc > /dev/null
if ($? == 0) then
    echo "${name}: the $class class requires the -2 syntax for the 2nd type"  ;
    echo "usage: $usage"  ;
    # the user does not get to see the mistakes (he might try to compile it)
    rm $out_h $out_cc ;
    exit 1;
endif ;

exit 0;
